#include "misc.h"

#define MAX_SEED_USAGE 24


int cryptHash ( BasicHashFunctionPtr cryptHashPtr, const char *passwd, unsigned char *outBuf )
{
   return cryptHashPtr((unsigned char *)passwd , strlen(passwd) , outBuf);
}

int MD5BasicHash ( const unsigned char *in,int len, unsigned char *outBuf)
{
  /* when you want to compute MD5, first, declere the next struct */
  MD5_CTX mdContext;
  /* then, init it before the first use */
  MD5Init (&mdContext);

  /* compute your string's hash using the next to calls */
  MD5Update (&mdContext, (unsigned char *)in, len);
  MD5Final (&mdContext);

  memcpy(outBuf,mdContext.digest,MD5_OUTPUT_LENGTH_IN_BYTES);
  return MD5_OUTPUT_LENGTH_IN_BYTES;
}

int SHA1BasicHash ( const unsigned char *in,int len, unsigned char *outBuf)
{
  /* when you want to compute SHA1, first, declere the next struct */
  SHA1Context sha;
  int i;
  /* then, init it before the first use */
  SHA1Reset(&sha);
  /* compute your string's hash using the next to calls */
  SHA1Input(&sha, (const unsigned char *) in, len);
  SHA1Result(&sha);
  
 for(i=0; i<5; ++i)	{
		outBuf[4 * i + 3] = (unsigned char)sha.Message_Digest[i] % 256;
	 	outBuf[4 * i + 2] = (unsigned char)((sha.Message_Digest[i] / 256) % 256);
	 	outBuf[4 * i + 1] = (unsigned char)((sha.Message_Digest[i] / (256 * 256)) % 256);
	 	outBuf[4 * i] = (unsigned char)((sha.Message_Digest[i] / (256 * 256 * 256))% 256);                    
}
 return SHA1_OUTPUT_LENGTH_IN_BYTES;
}


/* return 255 implies invalid hex char */
unsigned char hex2digit(char c) {
	if (c >= 48 && c <= 57)
		return c-48;
	if (c >= 65 && c <= 70)
		return c-55;
	if (c>=97 && c <= 102)
		return c-87;

	return 255;
}

/* return -1 implies invalid nibble */
char digit2hex(unsigned char c) {
	if (c<=9)
		return c+48;
	if (c>=10 && c<=15)
		return c+87;
	return -1;
}

/* returns -1 in case of either memory exeeding or bad hexa string */
int hexa2binary(const char *strIn, unsigned char *outBuf, int outMaxLen) {
	int i;
	int j = 0;
	int startingpoint = 0;
	int inlen = strlen(strIn);

	/* check if input is bigger than 0 */
	if (inlen == 0) {
		return -1;
	}

	/* check if enough space has been given for output */
	if ((outMaxLen*2 - inlen) < 0)
		return -1;

	/* check if string is a valid hexa string */
	for (i = 0; i < inlen; i++) {
		if (hex2digit(strIn[i]) == 255) return -1;
	}

	for(i = startingpoint; i+1 < inlen; i += 2, j++) {
		outBuf[j] = hex2digit(strIn[i+1]) | (hex2digit(strIn[i]) << 4);
	}

	if (strIn[i] != '\0') {
		outBuf[j] = hex2digit(strIn[i]);
		j++;
	}

	return j;
}

int binary2hexa(const unsigned char *bufIn, int lengthIn, char *outStr, int outMaxLen) {
	int i;
	int j=0;

	if (lengthIn*2 > outMaxLen-1) {
		if (outMaxLen > 0) {
			*outStr = '\0';
		}
		return -1;
	}

	for (i=0;i<lengthIn; i++, j+=2) {
		outStr[j] = digit2hex((bufIn[i] >> 4) & 0xf);
		outStr[j+1] = digit2hex(bufIn[i] & 0xf );
	}

	outStr[j] = '\0';

	return j+1; /* including '\0' in the count */
}


LONG_INDEX_PROJ pseudo_random_function(const unsigned char *x,int inputLength,LONG_INDEX_PROJ y)
/* You are allowed to change it or keep as is. Up to you*/
{
    LONG_INDEX_PROJ md5res[MD5_OUTPUT_LENGTH_IN_BYTES/sizeof(LONG_INDEX_PROJ)];
    unsigned char buffer4hashing[MAX_SEED_USAGE+sizeof(LONG_INDEX_PROJ)];
    
    if(inputLength>MAX_SEED_USAGE) inputLength = MAX_SEED_USAGE; 
        /*for efficiency purpose*/
    memcpy(buffer4hashing,x,inputLength);/*copy y itself*/
    memcpy(buffer4hashing+inputLength,&y,sizeof(LONG_INDEX_PROJ)); 
        /*concatenate step to the y*/ 
    MD5BasicHash( buffer4hashing, inputLength+sizeof(LONG_INDEX_PROJ) , (unsigned char *)md5res ); 
       /*main step, hash both y and index as fusion process*/ 
    /*now just harvest 63 bit out of 128*/
    return ((md5res[0])&0x7fffffffffffffff);     
}